﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using mshtml;
using System.Resources;
using System.CodeDom.Compiler;
using System.Diagnostics;
using System.IO;
using System.Configuration;
using System.Net;
using System.Threading; 

namespace BookInfoExtractor
{
    public partial class Form1 : Form
    {
        public static BookPattern objPattern = null;
        HtmlElement prevElement;
        HtmlElement element;
        int eventFireCnt;
        bool isSelected;
        Queue<string> urlQueue;
        public static List<BookInfo> lstBookInfo;

        bool isAuthorSelection;
        bool isTitleSelection;
        bool isImageSelection;
        bool isISBNSelection;
        bool isPriceSelection;
        bool areLinksDisabled = true;

        public Form1()
        {
            InitializeComponent();

            InitialiseForm();

        }

        private void InitialiseForm()
        {
            prevElement = null;
            element = null;
            eventFireCnt = 0;
            isSelected = false;

            isAuthorSelection = false;
            isTitleSelection = false;
            isImageSelection = false;
            isISBNSelection = false;
            isPriceSelection = false;

            objPattern = new BookPattern();
            lstBookInfo = new List<BookInfo>();
            
        }

        private void LoadUrls()
        {
            urlQueue = new Queue<string>();

            if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["UrlFilePath"]))
            {
                MessageBox.Show("Please open the BookInfoExtractor.exe.config file and set the UrlFilePath parameter to the full name of the input url text file and run tool again." + 
                    "\r\nPlease note that each new url should begin on a new line.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                Application.Exit();
            }

            if (!File.Exists(ConfigurationManager.AppSettings["UrlFilePath"]))
            {
                MessageBox.Show("File not found. Please make sure that text file containing url is present at the location specified in the config file and run tool again." +
                "\r\nPlease note that each new url should begin on a new line.",this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                Application.Exit();
            }

            foreach (string url in File.ReadAllLines(ConfigurationManager.AppSettings["UrlFilePath"]))
            {
                if(!string.IsNullOrEmpty(url.Trim()))
                    urlQueue.Enqueue(url);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //http://www.goodreads.com/shelf/show/favorites
            //http://www.popularprakashan.com/marathi.htm
            //http://www.barnesandnoble.com/u/books-top-100-bestsellers-of-the-year/379003535?start=1
            //http://www.openisbn.com/books/Business_Investing/
            //"http://www.barnesandnoble.com/u/books-top-100-bestsellers-of-the-year/379003535?start=1"
            LoadUrls();
            string csvHeaders = "ISBN, Title, Author, ImagePath, Price";

            if(string.IsNullOrEmpty(ConfigurationManager.AppSettings["OutputFile"]))
            {
                MessageBox.Show("Please open the BookInfoExtractor.exe.config file and set the OutputFile parameter to the full name of the output csv file and run tool again.",
                    this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                Application.Exit();
            }

            if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["ImgFilesDir"]))
            {
                MessageBox.Show("Please open the BookInfoExtractor.exe.config file and set the ImgFilesDir parameter to the full directory name of the output folder where image should be extracted and run tool again.",
                    this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                Application.Exit();
            }

            if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["ErrorLogFile"]))
            {
                MessageBox.Show("Umm, if an error occurs during extraction, there'll be no trace of what happened.\r\n" +
                "To help trace any possible errors, please open the BookInfoExtractor.exe.config file and set the ErrorLogFile parameter to the full name of the output error text file and run tool again.",
                this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                Application.Exit();
            }            

            File.WriteAllText(ConfigurationManager.AppSettings["OutputFile"], csvHeaders);
            webBrowser1.Url = new Uri(urlQueue.Dequeue());
            webBrowser1.ScriptErrorsSuppressed = true;
            toolStrip1.Visible = false;
            pnlPattern.Visible = false;
            btnToggleToolStrip.Enabled = false;
        }

        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            StringBuilder sbCSVContents;
            bool isPatternFound = false;
            if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
            {
                btnToggleToolStrip.Enabled = true;
                areLinksDisabled = true;
                foreach (HtmlElement anchorElement in webBrowser1.Document.Links)
                {
                    anchorElement.Click += new HtmlElementEventHandler(anchorElement_Click);
                    //HTMLAnchorElement obj = anchorElement.DomElement as HTMLAnchorElement;
                    //HTMLAnchorEvents_Event handler = obj as HTMLAnchorEvents_Event;
                    //handler.onclick += new HTMLAnchorEvents_onclickEventHandler(handler_onclick);
                }
                statusLblLinks.Text = "All links are disabled for this page.";

                //step by step - test all patterns, see if any of them matches with the page.
                //1 - Read patterns file, Get all patterns, loop through them
                //2 - for each pattern -> try match
                //3 - if match found i.e. node found, then apply pattern using similar class
                //4 - then extract all possible elements and store into csv

                DataSet dsPatterns = new DataSet();
                if (!File.Exists("Patterns.xml"))
                {
                    dsPatterns.Tables.Add(new DataTable());
                }
                else
                {
                    dsPatterns.ReadXml("Patterns.xml");
                }

                BookPattern foundPattern = new BookPattern();

                if (dsPatterns.Tables.Count == 0)
                    return;

                foreach (DataRow dRow in dsPatterns.Tables[0].Rows)
                {
                    HtmlElement patternElement = BookPattern.TryMatch(webBrowser1.Document, dRow["BaseElement"].ToString(), dRow["BaseElementID"].ToString(), dRow["BaseElementClassName"].ToString());

                    if (patternElement == null)
                    {
                        continue;
                    }

                    string[] delimiter = { "," };
                    foundPattern.Element = patternElement;
                    foundPattern.ClassNameToSearch = dRow["ClassNameToSearch"].ToString();
                    foundPattern.SetAuthorPosition(dRow["AuthorPosition"].ToString(), delimiter);
                    foundPattern.SetTitlePosition(dRow["TitlePosition"].ToString(), delimiter);
                    foundPattern.SetImagePosition(dRow["ImagePosition"].ToString(), delimiter);
                    foundPattern.SetISBNPosition(dRow["ISBNPosition"].ToString(), delimiter);
                    foundPattern.SetPricePosition(dRow["PricePosition"].ToString(), delimiter);
                    isPatternFound = true;
                    statusLblPatterns.Text = "Pattern found. Name: " + dRow["PatternName"].ToString();

                    foreach (HtmlElement node in BookPattern.ApplyPattern(patternElement, webBrowser1.Document, dRow["ClassNameToSearch"].ToString()))
                    {
                        BookInfo objBI = ExtractInfo(node, foundPattern);

                        if (objBI == null)
                            continue;

                        if (objBI.BookImage == null)
                        {
                            continue;
                        }

                        objBI.ISBN = "NA";
                        lstBookInfo.Add(objBI);
                    }

                }

                if (isPatternFound)
                {
                    ISBNLoader frmISBN = new ISBNLoader();
                    //ISBN logic should go here
                    Thread newThread = new Thread(new ThreadStart(frmISBN.LoadISBNExtractor));
                    newThread.SetApartmentState(ApartmentState.STA);
                    newThread.IsBackground = false;
                    newThread.Start();
                    Application.DoEvents();
                    newThread.Join();

                    if (!newThread.IsAlive)
                        newThread.Abort();

                    //frmISBN.FormLoader();

                    foreach (BookInfo _bi in lstBookInfo)
                    {
                        DownloadImageFile(_bi);

                        sbCSVContents = new StringBuilder();
                        sbCSVContents.AppendLine();
                        sbCSVContents.Append(_bi.ISBN);
                        sbCSVContents.Append(",");
                        sbCSVContents.Append("\"");
                        sbCSVContents.Append(_bi.Title);
                        sbCSVContents.Append("\"");
                        sbCSVContents.Append(",");
                        sbCSVContents.Append("\"");
                        sbCSVContents.Append(_bi.Author);
                        sbCSVContents.Append("\"");
                        sbCSVContents.Append(",");
                        sbCSVContents.Append(_bi.BookImage);
                        sbCSVContents.AppendLine();
                        File.AppendAllText(ConfigurationManager.AppSettings["OutputFile"], sbCSVContents.ToString());
                    }
                }
                else
                {
                    statusLblPatterns.Text = "No matching pattern found.";
                    if (urlQueue.Count == 0)
                    {
                        pnlElemSearch.Visible = true;
                        MessageBox.Show("No matching pattern found. \r\nPlease identify a pattern using the options available on the left.");
                    }
                    else
                        MessageBox.Show("No matching pattern found. \r\nMoving on to the next url in the list...");
                }

                if (urlQueue.Count > 0)
                {
                    webBrowser1.Navigate(urlQueue.Dequeue());
                    Application.DoEvents();
                    Thread.Sleep(2000);
                    InitialiseForm();
                }
                else
                {
                    MessageBox.Show("All URLs scanned, and book information extracted.");
                    webBrowser1.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
                    //webBrowser1 = null;
                }

            }
            //HtmlElement test = webBrowser1.Document.GetElementFromPoint(new Point(379, 493));

            //webBrowser1.Document.Click += new HtmlElementEventHandler(Document_Click);
            //webBrowser1.Document.MouseOver += new HtmlElementEventHandler(Document_MouseOver);
            //webBrowser1.Document.MouseLeave += new HtmlElementEventHandler(Document_MouseLeave);  
            //webBrowser1.Document.Body.AttachEventHandler("MouseOver", new HtmlElementEventHandler(void webBrowser1_MouseOver)); 

        }

        private void DownloadImageFile(BookInfo _bi)
        {
            WebClient objClient = null;

            try
            {
                objClient = new WebClient();
                string fileExtn = _bi.BookImage.Substring(_bi.BookImage.LastIndexOf("."));
                objClient.DownloadFile(_bi.BookImage, ConfigurationManager.AppSettings["ImgFilesDir"] + _bi.Title + "_" + _bi.ISBN + fileExtn);
                objClient.Dispose();
            }
            catch (Exception ex)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("\r\nBook Title: "); 
                sb.Append(_bi.Title);
                sb.AppendLine("Exception: Not able to download image");
                sb.AppendLine("Message: "); sb.Append(ex.Message);
                sb.AppendLine("Stack Trace: "); sb.Append(ex.StackTrace);
                File.AppendAllText(ConfigurationManager.AppSettings["ErrorLogFile"], sb.ToString());
                sb.Clear();
                sb = null;
            }
            finally
            {
                if (objClient != null)
                    objClient.Dispose();
            }
        }

        void anchorElement_Click(object sender, HtmlElementEventArgs e)
        {
            if(areLinksDisabled)
                e.ReturnValue = false;
        }

        bool handler_onclick()
        {
            if (areLinksDisabled)
                return false;
            else
                return true;
        }

        void Document_MouseLeave(object sender, HtmlElementEventArgs e)
        {
            prevElement = e.FromElement;
            prevElement.Style = null;  

            //if (prevElement != null && prevElement.Style != null)
            //{
            //    //border: 1px solid blue - tried this out, the Style property string actually contains the string below.
            //    //although when it was set, it was set as - "border: 1px solid blue"! :)
            //    //BORDER-BOTTOM: blue 1px solid; BORDER-LEFT: blue 1px solid; BORDER-TOP: blue 1px solid; BORDER-RIGHT: blue 1px solid
            //    string addedStyle = "BORDER-BOTTOM: blue 1px solid; BORDER-LEFT: blue 1px solid; BORDER-TOP: blue 1px solid; BORDER-RIGHT: blue 1px solid";
            //    int startIdx = prevElement.Style.IndexOf(addedStyle);
            //    if (startIdx != -1)
            //        prevElement.Style.Remove(startIdx, addedStyle.Length);
            //}
        }

        void Document_MouseOver(object sender, HtmlElementEventArgs e)
        {
            //HtmlElement elem = e.ToElement;
            if (!isSelected)
                return;

            Point ScreenCoord = new Point(MousePosition.X, MousePosition.Y);
            //! Browser coordinates
            Point BrowserCoord = webBrowser1.PointToClient(ScreenCoord);
            HtmlElement elem = webBrowser1.Document.GetElementFromPoint(BrowserCoord);
            elem.Style += "BORDER-BOTTOM: blue 1px solid; BORDER-LEFT: blue 1px solid; BORDER-TOP: blue 1px solid; BORDER-RIGHT: blue 1px solid";
            toolStripStatusLabel1.Text = "Element: " + elem.TagName;
            //e.FromElement.Style = "";
            //prevElement = elem;
        }

        void Document_Click(object sender, HtmlElementEventArgs e)
        {
            eventFireCnt += 1;
            if (eventFireCnt == 1)
            {
                if(isSelected)
                {
                    element = GetElementFromCoord();
                    objPattern.Element = element;
                    pnlElemSearch.Visible = false;
                    isSelected = false;
                }

                if (isAuthorSelection)
                {
                    objPattern.Author = GetElementFromCoord();
                    isAuthorSelection = false;
                }

                if (isTitleSelection)
                {
                    objPattern.Title = GetElementFromCoord();
                    isTitleSelection = false;
                }

                if (isImageSelection)
                {
                    objPattern.Image = GetElementFromCoord();
                    isImageSelection = false;
                }

                if (isISBNSelection)
                {
                    objPattern.ISBN = GetElementFromCoord();
                    isISBNSelection = false;
                }

                if (isPriceSelection)
                {
                    objPattern.Price = GetElementFromCoord();
                    isPriceSelection = false;
                }

                //working code - converted to function for repeat usage
                //Point ScreenCoord = new Point(MousePosition.X, MousePosition.Y);
                ////! Browser coordinates
                //Point BrowserCoord = webBrowser1.PointToClient(ScreenCoord);
                //element = webBrowser1.Document.GetElementFromPoint(BrowserCoord);

                //e.BubbleEvent = true;
                //webBrowser1.Document.Click -= Document_Click;
            }
            //webBrowser1.Document.MouseLeave -= new HtmlElementEventHandler(Document_MouseLeave);
            //webBrowser1.Document.MouseOver -= new HtmlElementEventHandler(Document_MouseOver);
            toolStripStatusLabel1.Text = "Element Selected: " + element.TagName;
        }

        private void btnToggleToolStrip_Click(object sender, EventArgs e)
        {
            if(toolStrip1.Visible == false) 
                toolStrip1.Visible = true;  
            else
                toolStrip1.Visible = false;  
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            if (!isSelected)
            {
                //webBrowser1.ContextMenuStrip = contextMenuStrip1;
                //webBrowser1.IsWebBrowserContextMenuEnabled = false; 
                webBrowser1.Document.Click += new HtmlElementEventHandler(Document_Click);
                webBrowser1.Document.MouseOver += new HtmlElementEventHandler(Document_MouseOver);
                webBrowser1.Document.MouseLeave += new HtmlElementEventHandler(Document_MouseLeave);
                isSelected = true;
                //toolStripButton1.Text = "Deselect";
                toolStripButton1.Enabled = false;  
                this.toolStripButton1.Image = ((System.Drawing.Image)(Properties.Resources.ResourceManager.GetObject("Deselect"))); 
            }
            //else
            //{
            //    //webBrowser1.IsWebBrowserContextMenuEnabled = true;
            //    System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
            //    webBrowser1.Document.Click -= new HtmlElementEventHandler(Document_Click);
            //    webBrowser1.Document.MouseOver -= new HtmlElementEventHandler(Document_MouseOver);
            //    webBrowser1.Document.MouseLeave -= new HtmlElementEventHandler(Document_MouseLeave);
            //    isSelected = false;
            //    toolStripButton1.Text = "Select";
            //    this.toolStripButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton1.Image"))); 
            //    element.Style = null;
            //}
        }

        private void btnFindSimilar_Click(object sender, EventArgs e)
        {
            //working code pushed to method FindPattern for repeat usage and extension
            //IEnumerable<HtmlElement> collElements = webBrowser1.Document.GetElementsByTagName(element.TagName).Cast<HtmlElement>();
            //dynamic domElement = element.DomElement;
            //string elemClass = domElement.className;
            ////IEnumerable<HtmlElement> matchedElements = collElements.Where(node => node.GetAttribute("class").StartsWith(element.GetAttribute("class")));
            //List<HtmlElement> lstElements = new List<HtmlElement>();
            //foreach(HtmlElement node in collElements)
            //{
            //    dynamic nodeDomElement = node.DomElement;
            //    string nodeClassName = nodeDomElement.className;
            //    if (nodeClassName != null && nodeClassName.Contains(txtClass.Text))   
            //    {
            //        lstElements.Add(node); 
            //        node.Style = "background-color:yellow";
            //    }
            //}

            foreach (HtmlElement node in FindPattern())
            {
                node.Style = "background-color:yellow";
            }
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            dynamic domElement = objPattern.Element.DomElement;
            string elemClass = domElement.className;

            pnlPattern.Visible = true;
            txtID.Text = objPattern.Element.Id;
            txtSelElement.Text = objPattern.Element.TagName;
            txtClass.Text = elemClass;
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            //objPattern.Element = element;
            objPattern.Author = GetElementFromCoord();
        }

        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            //objPattern.Element = element;
            objPattern.Title = GetElementFromCoord();
        }

        private void toolStripMenuItem3_Click(object sender, EventArgs e)
        {
            //objPattern.Element = element;
            objPattern.Image = GetElementFromCoord();
        }

        private void toolStripMenuItem4_Click(object sender, EventArgs e)
        {
            //objPattern.Element = element;
            objPattern.ISBN = GetElementFromCoord();
        }

        private HtmlElement GetElementFromCoord()
        {
            Point ScreenCoord = new Point(MousePosition.X, MousePosition.Y);
            //! Browser coordinates
            Point BrowserCoord = webBrowser1.PointToClient(ScreenCoord);
            HtmlElement elem = webBrowser1.Document.GetElementFromPoint(BrowserCoord);
            elem.Style = null;
            elem.Style = "BORDER-BOTTOM: red 1px dashed; BORDER-LEFT: red 1px dashed; BORDER-TOP: red 1px dashed; BORDER-RIGHT: red 1px dashed";
            toolStripStatusLabel1.Text = "Element: " + elem.TagName;
            return elem;
        }

        private void btnSavePattern_Click(object sender, EventArgs e)
        {
            Form2 frm = new Form2();
            frm.ShowDialog(); 
        }

        private void btnExtract_Click(object sender, EventArgs e)
        {
            foreach (HtmlElement node in FindPattern())
            {
                BookInfo objBI = ExtractInfo(node, objPattern);
            }
        }

        private BookInfo ExtractInfo(HtmlElement node, BookPattern pattern)
        {
            string authorValue = string.Empty;
            string titleValue = string.Empty;
            string imgSrc = string.Empty;
            string isbnValue = string.Empty;
            string detailsUrl = string.Empty;
            StringBuilder bookInfoExtractCode;
            BookInfo objBI;

            try
            {

                objBI = new BookInfo();

                //for each node 
                //get author position, and other attributes positions
                //below is generic logic to place those positions
                bookInfoExtractCode = new StringBuilder();

                //Get Author Position and generate dynamic code ready for execution
                bookInfoExtractCode.Append("public class DynamicBookInfoExtractor { public string GetAuthorValue(System.Windows.Forms.HtmlElement node) { return node");
                foreach (int pos in pattern.GetAuthorPosition())
                {
                    bookInfoExtractCode.Append(".Children[" + pos.ToString() + "]");
                }

                //GetAuthorValue func ends here
                bookInfoExtractCode.AppendLine(".InnerText; }");

                //Get Title Position and generate dynamic code ready for execution
                bookInfoExtractCode.Append("public string GetTitleValue(System.Windows.Forms.HtmlElement node) { return node");
                foreach (int pos in pattern.GetTitlePosition())
                {
                    bookInfoExtractCode.Append(".Children[" + pos.ToString() + "]");
                }

                //GetTitleValue func ends here
                bookInfoExtractCode.AppendLine(".InnerText; }");

                //Get Image Position and generate dynamic code ready for execution
                //code differs for extracting image, because we want image path and when we are taking children of the root node
                //at runtime, System.Windows.Forms.HtmlElement is insufficient to return image source.
                //Hence, we have to look to DomElement property of the same to get the source, thus using mshtml namespace
                //we can obtain iamge source. But returning DomElement via mshtml is proving complicated, so
                //return the img Element itself, and once obtained in this code we can do anything with it :)
                bookInfoExtractCode.Append("public System.Windows.Forms.HtmlElement GetImageSrc(System.Windows.Forms.HtmlElement node) { return node");
                foreach (int pos in pattern.GetImagePosition())
                {
                    bookInfoExtractCode.Append(".Children[" + pos.ToString() + "]");
                }

                //GetImageSrc func ends here
                bookInfoExtractCode.AppendLine(";}");


                //Get ISBN Position and generate dynamic code ready for execution
                bookInfoExtractCode.Append("public string GetISBNValue(System.Windows.Forms.HtmlElement node) { return node");
                foreach (int pos in pattern.GetISBNPosition())
                {
                    bookInfoExtractCode.Append(".Children[" + pos.ToString() + "]");
                }

                //GetISBNValue func ends here, class ends here :)
                bookInfoExtractCode.Append(".InnerText; }}");


                //->http://stackoverflow.com/questions/3188882/compile-and-run-dynamic-code-without-generating-exe
                //http://stackoverflow.com/questions/826398/is-it-possible-to-dynamically-compile-and-execute-c-sharp-code-fragments
                //below is sample code, the code for fooclass replace it with ur logic - build string at runtime
                //for func execute pass HtmlElement node parameter and specify it during the call to execute from Invoke method
                //as object param
                using (Microsoft.CSharp.CSharpCodeProvider objRunTimeCodeProvider =
                           new Microsoft.CSharp.CSharpCodeProvider())
                {
                    var res = objRunTimeCodeProvider.CompileAssemblyFromSource(
                        new System.CodeDom.Compiler.CompilerParameters(new string[] { "System.dll", "System.Windows.Forms.dll" })
                        {
                            GenerateInMemory = true,
                            GenerateExecutable = false
                        },
                        //"public class FooClass { public string Execute() { return \"output!\";}}"
                        //"public class FooClass { public string Execute(System.Windows.Forms.HtmlElement node) { return node.Children[3].Children[0].Children[1].Children[0].InnerText;}}"
                        bookInfoExtractCode.ToString()
                    );
                    res.Errors.Cast<CompilerError>().ToList().ForEach(error => Debug.WriteLine(error.ErrorText));
                    var type = res.CompiledAssembly.GetType("DynamicBookInfoExtractor");

                    var obj = Activator.CreateInstance(type);

                    authorValue = (string)type.GetMethod("GetAuthorValue").Invoke(obj, new object[] { node });
                    titleValue = (string)type.GetMethod("GetTitleValue").Invoke(obj, new object[] { node });
                    HtmlElement imgElement = (HtmlElement)type.GetMethod("GetImageSrc").Invoke(obj, new object[] { node });
                    imgSrc = ((IHTMLImgElement)imgElement.DomElement).src;
                    
                    HtmlElement detailsUrlElement = imgElement.Parent;
                    dynamic anchorDetailsUrl = detailsUrlElement.DomElement;
                    detailsUrl = anchorDetailsUrl.href;

                    isbnValue = (string)type.GetMethod("GetISBNValue").Invoke(obj, new object[] { node });

                    objBI.Author = authorValue;
                    objBI.Title = titleValue;
                    objBI.ISBN = isbnValue;
                    objBI.BookImage = imgSrc;
                    objBI.SourceUrl = node.Document.Url.ToString();
                    if (!detailsUrl.Contains("http"))
                    {
                        detailsUrl = node.Document.Url.AbsolutePath + detailsUrl;
                    }
                    objBI.DetailsUrl = detailsUrl;
                    
                    return objBI;
                }
            }
            catch(Exception ex)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("\r\nUrl: " + node.Document.Url);
                sb.AppendLine();
                sb.AppendLine("Node Outer HTML: " + node.OuterHtml);
                sb.AppendLine();
                sb.AppendLine("Exception Message: " + ex.Message);
                sb.AppendLine();
                sb.AppendLine("Exception Stack Trace: " + ex.StackTrace);
                sb.AppendLine();
                File.AppendAllText(ConfigurationManager.AppSettings["ErrorLogFile"], sb.ToString());
                sb.Clear();
                sb = null;
            }

            return null;
        }

        private List<HtmlElement> FindPattern()
        {
            IEnumerable<HtmlElement> collElements = webBrowser1.Document.GetElementsByTagName(element.TagName).Cast<HtmlElement>();
            dynamic domElement = element.DomElement;
            string elemClass = domElement.className;
            //IEnumerable<HtmlElement> matchedElements = collElements.Where(node => node.GetAttribute("class").StartsWith(element.GetAttribute("class")));
            List<HtmlElement> lstElements = new List<HtmlElement>();

            objPattern.ClassNameToSearch = txtClass.Text;

            foreach (HtmlElement node in collElements)
            {
                dynamic nodeDomElement = node.DomElement;
                string nodeClassName = nodeDomElement.className;
                if (nodeClassName != null && nodeClassName.Contains(txtClass.Text))
                {
                    lstElements.Add(node);
                    //node.Style = "background-color:yellow";
                }
            }

            return lstElements;
        }

        private void selectTitleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            isTitleSelection = true;
            eventFireCnt = 0;
        }

        private void selectAuthorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            isAuthorSelection = true;
            eventFireCnt = 0;
        }

        private void selectImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            isImageSelection = true;
            eventFireCnt = 0;
        }

        private void selectISBNToolStripMenuItem_Click(object sender, EventArgs e)
        {
            isISBNSelection = true;
            eventFireCnt = 0;
        }

        private void selectPriceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            isPriceSelection = true;
            eventFireCnt = 0;
        }

        private void btnEnableLinks_Click(object sender, EventArgs e)
        {
            areLinksDisabled = false;
            statusLblLinks.Text = "All links are enabled for this page.";
            statusLblLinks.ForeColor = Color.Blue;
        }

        private void btnSelSearch_Click(object sender, EventArgs e)
        {
            HtmlElement searchedElement = webBrowser1.Document.GetElementById(txtSelID.Text);
            if (searchedElement == null)
            {
                foreach(HtmlElement elem in webBrowser1.Document.Body.All)
                {
                    dynamic srchDomElem = elem.DomElement;
                    string className = srchDomElem.className;

                    if (!radioButton1.Checked)
                    {
                        if (!string.IsNullOrEmpty(className) && className.ToLower().Contains(txtSelID.Text.ToLower()))
                        {
                            searchedElement = elem;
                        }

                        if (searchedElement != null)
                        {
                            HtmlElement tempChild = webBrowser1.Document.CreateElement("span");
                            tempChild.Style = "color: green; font-size:xx-small; font-style:normal;";
                            tempChild.InnerText = "class: " + className;
                            searchedElement.AppendChild(tempChild);
                        }
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(className) && className.ToLower() == txtSelID.Text.ToLower())
                        {
                            searchedElement = elem;
                        }

                        if (searchedElement != null)
                        {
                            HtmlElement tempChild = webBrowser1.Document.CreateElement("span");
                            tempChild.Style = "color: green; font-size:xx-small; font-style:normal;";
                            tempChild.InnerText = "class: " + className;
                            searchedElement.AppendChild(tempChild);
                            break;
                        }
                    }
                }
            }
            else
            {
                searchedElement.Style = "BORDER-BOTTOM: blue 1px solid; BORDER-LEFT: blue 1px solid; BORDER-TOP: blue 1px solid; BORDER-RIGHT: blue 1px solid";
                toolStripStatusLabel1.Text = "Element: " + searchedElement.TagName;
            }

        }


    }
}
